#include "attendancechecker.h"
#include "attendancerulesservice.h"
#include "attendservice.h"
#include "sqlitemanager.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QDateTime>

AttendanceChecker::AttendanceChecker(AttendanceRulesService *rulesService,
                                     AttendService *attendService,
                                     QObject *parent)
    : QObject(parent),
      m_rulesService(rulesService),
      m_attendService(attendService)
{
    Q_ASSERT(rulesService != nullptr);
    Q_ASSERT(attendService != nullptr);
}

QJsonObject AttendanceChecker::getApplicableRule(const QString &employeeId)
{
    // 获取默认规则（标准工时制）
    QJsonArray defaultRules = m_rulesService->getRulesByName("标准工时制");
    if (defaultRules.isEmpty()) {
        qWarning() << "No default attendance rule found";
        return QJsonObject();
    }
    return defaultRules.first().toObject();
}

AttendanceChecker::CheckStatus AttendanceChecker::judgeSignInStatus(const QTime &signInTime, const QJsonObject &rule)
{
    if (!isValidTime(signInTime)) {
        return CheckStatus::NO_RECORD;
    }

    // 从规则中获取关键时间点
    QTime earliestCheckin = getTimeFromRule(rule, "checkin_start");  // 最早签到时间
    QTime workStart = getTimeFromRule(rule, "work_start");              // 上班时间
    QTime splitTime = getTimeFromRule(rule, "split_time");              // 分割时间

    // 签到逻辑：
    // 1. 早于最早签到时间 → 无效（缺卡）
    if (signInTime < earliestCheckin) {
        return CheckStatus::NO_RECORD;
    }
    // 2. 最早签到时间 至 上班时间 → 正常
    else if (signInTime <= workStart) {
        return CheckStatus::NORMAL;
    }
    // 3. 上班时间 至 分割时间 → 迟到
    else if (signInTime <= splitTime) {
        return CheckStatus::LATE;
    }
    // 4. 超过分割时间 → 缺勤
    else {
        return CheckStatus::ABSENT;
    }
}

AttendanceChecker::CheckStatus AttendanceChecker::judgeSignOutStatus(const QTime &signOutTime, const QJsonObject &rule)
{
    if (!isValidTime(signOutTime)) {
        return CheckStatus::NO_RECORD;
    }

    // 从规则中获取关键时间点
    QTime workEnd = getTimeFromRule(rule, "work_end");              // 下班时间
    QTime splitTime = getTimeFromRule(rule, "split_time");          // 分割时间
    QTime latestCheckout = getTimeFromRule(rule, "checkout_end");// 最晚签退时间

    // 签退逻辑：
    // 1. 晚于最晚签退时间 → 无效（缺卡）
    if (signOutTime > latestCheckout) {
        return CheckStatus::NO_RECORD;
    }
    // 2. 下班时间 至 最晚签退时间 → 正常
    else if (signOutTime >= workEnd) {
        return CheckStatus::NORMAL;
    }
    // 3. 分割时间 至 下班时间 → 早退
    else if (signOutTime >= splitTime) {
        return CheckStatus::EARLY_LEAVE;
    }
    // 4. 早于分割时间 → 缺勤
    else {
        return CheckStatus::ABSENT;
    }
}

QString AttendanceChecker::statusToString(CheckStatus status)
{
    switch (status) {
    case CheckStatus::NORMAL: return "正常";
    case CheckStatus::LATE: return "迟到";
    case CheckStatus::EARLY_LEAVE: return "早退";
    case CheckStatus::ABSENT: return "缺勤";
    case CheckStatus::NO_RECORD: return "缺卡";
    case CheckStatus::LEAVE_MORNING: return "上午请假";
    case CheckStatus::LEAVE_AFTERNOON: return "下午请假";
    case CheckStatus::LEAVE_FULL: return "全天请假";
    default: return "无效";
    }
}

bool AttendanceChecker::processCheckInOut(const QString &employeeId, const QString &currentDateTime)
{
    QDateTime dt = QDateTime::fromString(currentDateTime, "yyyy-MM-dd HH:mm:ss");
    if (!dt.isValid()) {
        qWarning() << "Invalid datetime format:" << currentDateTime;
        return false;
    }

    QString recordDate = dt.toString("yyyy-MM-dd");
    QTime currentTime = dt.time();
    QJsonObject rule = getApplicableRule(employeeId);

    if (rule.isEmpty()) {
        return false;
    }

    // 根据分割时间判断打卡类型（签到/签退）
    QTime splitTime = getTimeFromRule(rule, "split_time");
    QString checkType = (currentTime <= splitTime) ? "in" : "out";

    // 检查是否已请假（仅拦截当前时段的请假）
    QJsonObject attendStatus = m_attendService->getAttendStatusByEmployeeIdAndDate(employeeId, recordDate);
    if (!attendStatus.isEmpty()) {
        QString signIn = attendStatus["signInStatus"].toString();
        QString signOut = attendStatus["signOutStatus"].toString();

        // 仅在当前是签到且上午/全天请假时拦截
        if ((signIn == "上午请假" || signIn == "全天请假") && checkType == "in") {
            qWarning() << "Cannot check in: morning or full day leave exists";
            return false;
        }
        // 仅在当前是签退且下午/全天请假时拦截
        if ((signOut == "下午请假" || signOut == "全天请假") && checkType == "out") {
            qWarning() << "Cannot check out: afternoon or full day leave exists";
            return false;
        }
    }

    // 计算状态
    CheckStatus status = (checkType == "in")
            ? judgeSignInStatus(currentTime, rule)
            : judgeSignOutStatus(currentTime, rule);

    return m_attendService->addOrUpdateAttendRecord(
                employeeId,
                recordDate,
                currentTime.toString("HH:mm:ss"),
                checkType,
                statusToString(status),
                getTimeFromRule(rule, "work_start"),
                getTimeFromRule(rule, "work_end"),
                getTimeFromRule(rule, "split_time")
                );
}

bool AttendanceChecker::isValidTime(const QTime &time)
{
    return time.isValid() && time >= QTime(0, 0, 0) && time <= QTime(23, 59, 59);
}

QTime AttendanceChecker::getTimeFromRule(const QJsonObject &rule, const QString &key)
{
    return QTime::fromString(rule[key].toString(), "HH:mm:ss");
}

bool AttendanceChecker::isCheckInWithinAllowedTime(const QString &employeeId, const QDateTime &currentDateTime)
{
    QDateTime dt = currentDateTime;
    if (!dt.isValid()) {
        qWarning() << "[AttendanceChecker] Invalid datetime format:" << currentDateTime;
        return false;
    }
    QTime currentTime = dt.time();

    // 获取员工适用的考勤规则
    QJsonObject rule = getApplicableRule(employeeId);
    if (rule.isEmpty()) {
        qWarning() << "[AttendanceChecker] No applicable rule for employee:" << employeeId;
        return false;
    }

    // 从规则中提取关键时间点
    QTime earliestCheckin = getTimeFromRule(rule, "checkin_start");  // 最早签到时间
    QTime splitTime = getTimeFromRule(rule, "split_time");              // 分割时间（区分签到/签退）
    QTime latestCheckout = getTimeFromRule(rule, "checkout_end");    // 最晚签退时间

    // 判断打卡类型（签到/签退），并校验是否在对应允许时间范围内
    if (currentTime <= splitTime) {
        // 签到：允许时间范围 → 最早签到时间 ≤ 打卡时间 ≤ 分割时间
        bool isWithinSignInTime = (currentTime >= earliestCheckin) && (currentTime <= splitTime);
        if (!isWithinSignInTime) {
            qDebug() << "[AttendanceChecker] Sign-in time out of range. Employee:" << employeeId
                     << "CurrentTime:" << currentTime.toString()
                     << "AllowedRange:" << earliestCheckin.toString() << "-" << splitTime.toString();
        }
        return isWithinSignInTime;
    } else {
        // 签退：允许时间范围 → 分割时间 < 打卡时间 ≤ 最晚签退时间
        bool isWithinSignOutTime = (currentTime > splitTime) && (currentTime <= latestCheckout);
        if (!isWithinSignOutTime) {
            qDebug() << "[AttendanceChecker] Sign-out time out of range. Employee:" << employeeId
                     << "CurrentTime:" << currentTime.toString()
                     << "AllowedRange:" << splitTime.toString() << "-" << latestCheckout.toString();
        }
        return isWithinSignOutTime;
    }
}

bool AttendanceChecker::isDuplicateCheckIn(const QString &employeeId, const QDateTime &currentDateTime, const QString &checkType)
{
    if (employeeId.isEmpty() || !currentDateTime.isValid() || (checkType != "in" && checkType != "out")) {
        qWarning() << "[AttendanceChecker] Invalid parameters for duplicate check";
        return false;
    }

    // 提取当前打卡日期（yyyy-MM-dd）
    QString recordDate = currentDateTime.toString("yyyy-MM-dd");

    // 调用 AttendService 的方法检测重复打卡（核心修改）
    bool isDuplicate = m_attendService->isAttendRecordExists(employeeId, recordDate, checkType);

    // 打印日志
    if (isDuplicate) {
        qDebug() << "[AttendanceChecker] Duplicate check confirmed. Employee:" << employeeId
                 << "Date:" << recordDate << "Type:" << checkType;
    }

    return isDuplicate;
}

bool AttendanceChecker::processLeave(const QString &employeeId, const QString &recordDate, CheckStatus leaveType)
{
    QString leaveStr = statusToString(leaveType);
    bool updateSuccess = false;

    // 获取当前状态（可能为空）
    QJsonObject existingStatus = m_attendService->getAttendStatusByEmployeeIdAndDate(employeeId, recordDate);
    bool hasRecord = !existingStatus.isEmpty();

    if (leaveType == CheckStatus::LEAVE_MORNING) {
        // 上午请假：更新签到状态为上午请假，签退状态保持不变或默认缺卡
        updateSuccess = m_attendService->updateLeaveStatus(
                    employeeId,
                    recordDate,
                    leaveStr,
                    hasRecord ? existingStatus["signOutStatus"].toString() : "缺卡"
                    );
    }
    else if (leaveType == CheckStatus::LEAVE_AFTERNOON) {
        // 下午请假：更新签退状态为下午请假，签到状态保持不变或默认缺卡
        updateSuccess = m_attendService->updateLeaveStatus(
                    employeeId,
                    recordDate,
                    hasRecord ? existingStatus["signInStatus"].toString() : "缺卡",
                    leaveStr
                    );
    }
    else if (leaveType == CheckStatus::LEAVE_FULL) {
        // 全天请假：同时更新签到和签退状态
        updateSuccess = m_attendService->updateLeaveStatus(
                    employeeId,
                    recordDate,
                    leaveStr,
                    leaveStr
                    );
    }

    return updateSuccess;
}
